/* Copyrights Security Engineering Research Group 
 * Author: Nauman (http://recluze.wordpress.com) 
 * 
 */

package edu.serg.mbar.ucon;

import java.io.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import org.apache.log4j.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource; //import com.sun.org.apache.xpath.internal.CachedXPathAPI;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xml.utils.PrefixResolverDefault;
import org.apache.xpath.CachedXPathAPI;
import org.apache.xpath.jaxp.JAXPPrefixResolver;
import org.apache.xml.serializer.*;

import edu.serg.mbar.ucon.meta.MBARNamespaceContext;
import edu.serg.mbar.ucon.meta.RegisteredStrings;
import edu.serg.utils.XMLUtils;

// if you get this error: 
// Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/xml/serializer/TreeWalker
// you may need to download serializer.jar. 
// Refer to http://www.java2s.com/Code/Jar/Apache/Downloadserializerjar.htm

/**
 * This class performs subject authentication based on the ID and secret
 * provided to it. It reads the subject authentication information from a
 * director containing [subjects].xml
 * 
 * @author Nauman (recluze.wordpress.com)
 * 
 */
public class AuthenticationManager {

	static Logger log = Logger.getLogger(AuthenticationManager.class);

	/**
	 * The directory containing the subjects meta information. To be changed
	 * later to read from a config file.
	 */
	private final static String SUBJECTS_DIR = RegisteredStrings.SUBJECTS_DIR;

	/**
	 * Authenticate a user with the provided secret.
	 * 
	 * @param subjectID
	 *            The unique ID of the subject
	 * @param subjectSecret
	 *            The secret of the subject
	 * @return A Map of attributes.
	 * 
	 * @throws AuthenticationFailedException
	 * 
	 */
	/*
	 * 													Previous Signature/definition of the Function
	 * 
	 * public Map<String, Vector<String>> authenticate(String subjectID,
			String subjectSecret) throws AuthenticationFailedException {
	 */
	public void authenticate(String subjectID,
			String subjectSecret) throws AuthenticationFailedException {

		XMLUtils xmlUtils = new XMLUtils();

		log.info("Authenticating user: " + subjectID);

		String filename = SUBJECTS_DIR + subjectID + ".xml";
		log.debug("Using XPath to read the subject information from file: "
				+ filename);

		String xpath = "//obj:Object[obj:ObjectID/text()='" + subjectID
				+ "']/obj:Secret/text()";

		log.debug("Resolving subjectSecret using XPath: " + xpath);
		String foundSecret = "";
		try {
			foundSecret = xmlUtils.xPathEvaluateToString(xmlUtils
					.parseXmlFromFile(filename), xpath);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
		}

		if (!foundSecret.equals(subjectSecret)) {
			log.info("No subject with that ID/Secret found.");
			throw new AuthenticationFailedException("Invalid SubjectID/Secret");
		}
		log.info("Authentication succeeded for subject: " + subjectID);

		/*// use AttributeManager for attribute resolution
		log.debug("Initializing the HashMap");
		Map<String, Vector<String>> attributesMap = new HashMap<String, Vector<String>>();

		log.debug("Collecting attributes of the subject in the HashMap");

		log.debug("Using XPath to read subject attributes from file: "
				+ filename);

		xpath = "//sub:Subject[obj:ObjectID/text()='" + subjectID
				+ "']/obj:Attributes/obj:Attribute";
		log.debug("Resolving subject attributes using XPath: " + xpath);

		
		
		Document doc = null;
		Node n = null;
		NodeIterator nl = null;

		doc = null;
		n = null;
		nl = null;
		
		try {
			InputSource in = new InputSource(new FileInputStream(filename));
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setNamespaceAware(true);
			doc = dbf.newDocumentBuilder().parse(in);

			CachedXPathAPI path = new CachedXPathAPI();
			nl = path.selectNodeIterator(doc, xpath);

		} catch (Exception e) {
			log.error(e.getMessage());

			// throw an Exception corresponding to the error
			throw new AuthenticationFailedException();
		}

		try {
			Transformer trans = TransformerFactory.newInstance().newTransformer();
			trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

			System.out.println("");

			while ((n = nl.nextNode()) != null) {

				// in "n", we have a node. Let's parse it!
				log.debug("Parsing attribute node");

			}

			System.out.println("");
		} catch (Exception e) {
				log.error(e.getMessage());

		}
		// while ((n = nl.nextNode()) != null) {
		//
		// }

		log
				.info("For the time being assuming no attributes. Returning mbar:USER_ID attribute noly");
		Vector<String> userIdVals = new Vector<String>();
		userIdVals.add(subjectID);
		attributesMap.put("mbar:USER_ID", userIdVals);
		log.debug("Put attribute: " + "mbar:USER_ID = " + subjectID);

		log.debug("Returning the attributesMap of length : "
				+ attributesMap.size());
		log.debug(attributesMap.toString());
		return attributesMap;*/
	}
}
